/*************************************************
 * 
 * Copyright by Bruno Eberhard
 * 
 * Created on 01.08.2005
 *
 *************************************************/
package fightplan.business;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class Fight implements Serializable {
	private static final long serialVersionUID = 1L;

	private List<FightEntry> entries;
	private List<ResultHolder> result;

	private Plan plan;

	private String name = "";

	private long stamp;

	Fight(Plan plan) {
		this.stamp = System.nanoTime();
		this.plan = plan;
		this.entries = new ArrayList<FightEntry>();
		this.result = new ArrayList<ResultHolder>();
	}

	// get / set

	public int getFighterCount() {
		return entries.size();
	}

	public List<FightEntry> getFightEntries() {
		return entries;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Plan getPlan() {
		return plan;
	}

	//

	public FighterProvider getFighter(int pos) {
		if (pos < entries.size()) {
			return entries.get(pos).getFighterProvider();
		} else {
			return null;
		}
	}

	public ResultHolder getResultHolder(int pos) {
		while (result.size() <= pos) {
			result.add(new ResultHolder(this, result.size()));
		}
		return result.get(pos);
	}

	public FighterHolder getWinResultHolder() {
		return getResultHolder(0);
	}

	public String getDisplayResult() {
		AbstractFighter winner = getWinResultHolder().getFighter();
		if (winner != null) {
			return winner.getName() + " gewinnt";
		}
		return "offen";
	}

	// use with care
	public void setWinner(AbstractFighter fighter) {
		for (FightEntry entry : entries) {
			if (entry.getFighter().equals(fighter)) {
				entry.setResult(Result.WON);
			} else if (entry.getResult().equals(Result.WON)) {
				entry.setResult(Result.LOST);
			}
		}
	}

	public void addFighter(FighterProvider fighter) {
		FightEntry entry = new FightEntry(this, fighter);
		entries.add(entry);
		getResultHolder(entries.size() - 1); // asserts availibility
	}

	void entryChanged(FightEntry entry) {
		makeConsistentFor(entry);
		updateResult();
	}

	private void updateResult() {
		if (entries.size() == 1) {
			result.get(0).setFighter(entries.get(0).getFighter());
		} else if (entries.size() == 2) {
			if (entries.get(0).getResult().equals(Result.WON)) {
				result.get(0).setFighter(entries.get(0).getFighter());
				result.get(1).setFighter(entries.get(1).getFighter());
			} else if (entries.get(1).getResult().equals(Result.WON)) {
				result.get(1).setFighter(entries.get(0).getFighter());
				result.get(0).setFighter(entries.get(1).getFighter());
			}
		} else {
			updateScoreResult();
		}
	}

	private void updateScoreResult() {
		// #1 13.3
		// #2 14.4
		// #3 11.2
		// #4 13.3
		// ->
		// 1. #2
		// 2. #1
		// 2. #4
		// 4. #3

		for (int i = 0; i < entries.size(); i++) {
			getResultHolder(i).setFighter(null);
			getResultHolder(i).setRank(-1);
		}

		for (FightEntry entry : entries) {
			// Die Anzahl besser klassierter Teilnehmer ermitteln
			int rank = 0;
			for (FightEntry entry2 : entries) {
				if (entry2.getOverallScore() > entry.getOverallScore()) {
					rank++;
				}
			}

			// Eine freie Position suchen
			int pos = rank;
			while (getResultHolder(pos).getFighter() != null) {
				pos++;
			}
			getResultHolder(pos).setFighter(entry.getFighter());
			getResultHolder(pos).setRank(rank);
		}
	}

	private void makeConsistentFor(FightEntry entry) {
		if (entries.size() == 2) {
			FightEntry otherEntry = entries.get(0) == entry ? entries.get(1) : entries.get(0);
			if (Result.isPositive(entry.getResult())
					&& (Result.isPositive(otherEntry.getResult()) || Result.isOpen(otherEntry.getResult()))) {
				otherEntry.setResult(Result.LOST);
			} else if (Result.isNegative(entry.getResult())
					&& (Result.isOpen(otherEntry.getResult()) || Result.LOST.equals(otherEntry.getResult()))) {
				otherEntry.setResult(Result.WON);
			}
		}
	}

	@Override
	public boolean equals(Object obj) {
		if (!(obj instanceof Fight))
			return false;
		Fight f2 = (Fight) obj;
		return stamp == f2.stamp;
	}

	@Override
	public int hashCode() {
		return (int) stamp;
	}

}